#if defined(_WIN32)
#pragma warning( disable : 4819)
#endif

#include <boost/foreach.hpp>

#include <CGAL/assertions.h>

#include "Connected_components.h"
#include "basic_typedef.h"

/////////////////
//CTR's & DTR's//
/////////////////

Connected_components::Connected_components() :_id(0)
{
  elem_cc_map.clear();
  id_cc_map.clear();
}

Connected_components::~Connected_components() {}

/////////////////
//set functions//
/////////////////

void Connected_components::add_element(int elem_id)
{
  CGAL_precondition (elem_cc_map.find(elem_id) == elem_cc_map.end());
  
  int cc_id = get_new_cc_id();
  
  Connected_component  cc;
  Int_int_map uu;
  cc.insert(elem_id);
  
  elem_cc_map[elem_id] = cc_id;
  id_cc_map[cc_id] = cc;
}
void Connected_components::connect_elements(int elem_id1,int elem_id2)
{
  CGAL_precondition (elem_cc_map.find(elem_id1) != elem_cc_map.end());
  CGAL_precondition (elem_cc_map.find(elem_id2) != elem_cc_map.end());

  int cc1_id;
  Int_int_map_iter  iter1 = elem_cc_map.find(elem_id1);
  cc1_id = iter1->second;

  int cc2_id;
  Int_int_map_iter  iter2 = elem_cc_map.find(elem_id2);
  cc2_id = iter2->second;

  //if in same cc return;
  if (cc1_id == cc2_id) return ;
  
  Connected_component & cc2 = id_cc_map[cc2_id];

  //merge into int_set_ptr1
  id_cc_map[cc1_id].insert(cc2.begin(),cc2.end());
  BOOST_FOREACH (int id , cc2) elem_cc_map[id] = cc1_id;
  id_cc_map.erase(cc2_id);
}

/////////////////
//get functions//
/////////////////
Connected_component& Connected_components::get_connected_component(int elem_id)
{
  CGAL_precondition (elem_cc_map.find(elem_id)!=elem_cc_map.end());
  return id_cc_map[elem_cc_map[elem_id]];
}
int            Connected_components::get_connected_component_id(int elem_id)
{
  return ((elem_cc_map.find(elem_id)!=elem_cc_map.end()) ?
          elem_cc_map[elem_id] : -1);
}

std::map<int, Connected_component>&
Connected_components::get_connected_components()
{
  return id_cc_map;
}

bool
Connected_components::is_in_same_connected_component(int elem_id1,
                                                     int elem_id2)
{
  Int_int_map_iter iter1 = elem_cc_map.find(elem_id1);
  Int_int_map_iter iter2 = elem_cc_map.find(elem_id2);
  if ((iter1 == elem_cc_map.end()) || (iter2 == elem_cc_map.end()))
    return false;
  return (iter1->second == iter2->second);
}
/////////////////////
//dbg functions//
/////////////////////
void Connected_components::print_connected_components()
{
  std::cout   << "There are " << id_cc_map.size() << " connected components"
              << std::endl;
  std::cout   << "cc id" << "|" << "cc elemnts" << std::endl;
  std::cout   << "-----" << "|" << "--------------------" << std::endl;
  Int_cc_map::iterator iter;
  for (iter = id_cc_map.begin(); iter != id_cc_map.end(); ++iter) {
    print_connected_component(iter->first);
  }
}
void Connected_components::print_connected_component(int cc_id)
{
  Int_cc_map::iterator iter = id_cc_map.find(cc_id);
  if (iter == id_cc_map.end()) return;
  
  std::cout << iter->first << "    |";
  BOOST_FOREACH(int elem, iter->second) std::cout << elem << ", ";
  std::cout << std::endl;
}

/////////////////////
//private functions//
/////////////////////
int Connected_components::get_new_cc_id()
{
  return _id++;
}

int Connected_components::get_num_connected_components()
{
  return id_cc_map.size();
}
